package studyguide.ch12;

import java.io.IOException;
import java.util.Date;

import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.ChoiceGroup;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.TextField;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import javax.microedition.rms.InvalidRecordIDException;
import javax.microedition.rms.RecordEnumeration;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import javax.microedition.rms.RecordStoreFullException;
import javax.microedition.rms.RecordStoreNotFoundException;
import javax.microedition.rms.RecordStoreNotOpenException;

public class RMSMidlet extends MIDlet {

	private final Command addCommand;
	private final Command deleteCommand;
	private final Command exitCommand;
	private final Display display;
	
	private final Form mainForm;
	private final TextField nameField;
	private final TextField ageField;
	private final ChoiceGroup adultsList;
	private final ChoiceGroup kidsList;
	
	private RecordStore recordStore;
	
	private class SampleCommandListener implements CommandListener {
		public void commandAction(Command command, Displayable displayable) {
			try {
				if (command == exitCommand) {
					destroyApp(true);
					notifyDestroyed();
				} else if (command == addCommand) {
					String name = nameField.getString().trim();
					String age = ageField.getString().trim();
					if (!"".equals(name) && !"".equals(age)) {
						Person person = new Person(name, Integer.parseInt(age));
						// Add to persistence:
						byte[] personData = person.serialize();
						recordStore.addRecord(personData, 0, personData.length);
						// Add to presentation:
						if (person.getAge() >= 18) {
							adultsList.append(person.toString(), null);
						} else {
							kidsList.append(person.toString(), null);
						}
					}
				} else if (command == deleteCommand) {
					RecordEnumeration records = recordStore.enumerateRecords(null, null, false);
					while (records.hasNextElement()) {
						recordStore.deleteRecord(records.nextRecordId());
					}
					adultsList.deleteAll();
					kidsList.deleteAll();
				} else {
					throw new RuntimeException("UNKNOWN COMMAND" + command);
				}
			} catch (RecordStoreNotOpenException e) {
				throw new RuntimeException(e.getMessage());
			} catch (RecordStoreFullException e) {
				throw new RuntimeException(e.getMessage());
			} catch (RecordStoreException e) {
				throw new RuntimeException(e.getMessage());
			}
		}
	}
	
	public RMSMidlet() throws IOException {
		mainForm = new Form("RMS Sample");
		exitCommand = new Command("Exit", Command.EXIT, 1);
		addCommand = new Command("Add", Command.SCREEN, 1);
		deleteCommand = new Command("Delete Everything", Command.SCREEN, 2);
		
		mainForm.addCommand(addCommand);
		mainForm.addCommand(deleteCommand);
		mainForm.addCommand(exitCommand);
		
		SampleCommandListener listener = new SampleCommandListener();
		mainForm.setCommandListener(listener);
		display = Display.getDisplay(this);
		
		nameField = new TextField("Name", "", 10, TextField.ANY);
		ageField = new TextField("Age", "", 2, TextField.NUMERIC);
		adultsList = new ChoiceGroup("Adults", Choice.MULTIPLE);
		kidsList = new ChoiceGroup("Kids", Choice.MULTIPLE);
		
		mainForm.append(nameField);
		mainForm.append(ageField);
		mainForm.append(adultsList);
		mainForm.append(kidsList);
	}
	
	protected void destroyApp(boolean unconditional) {
		closeDatabase();
	}

	protected void pauseApp() {
		closeDatabase();
	}

	protected void startApp() throws MIDletStateChangeException {
		try {
			display.setCurrent(mainForm);
			openDatabase();
			// Sorts by age:
			PersonComparator comparator = new PersonComparator();
			
			// Update presentation with database status
			adultsList.deleteAll();
			kidsList.deleteAll();

			// Get all adults
			PersonAgeFilter filter = new PersonAgeFilter(18, true);
			RecordEnumeration records = recordStore.enumerateRecords(filter, comparator, false);
			while (records.hasNextElement()) {
				byte[] serializedData = records.nextRecord();
				Person person = new Person(serializedData);
				adultsList.append(person.toString(), null);
			}
			records.destroy();
			
			// Get all kids
			filter = new PersonAgeFilter(18, false);
			records = recordStore.enumerateRecords(filter, comparator, false);
			while (records.hasNextElement()) {
				byte[] serializedData = records.nextRecord();
				Person person = new Person(serializedData);
				kidsList.append(person.toString(), null);
			}
			records.destroy();
			
		} catch (RecordStoreNotOpenException e) {
			throw new MIDletStateChangeException(e.getMessage());
		} catch (InvalidRecordIDException e) {
			throw new MIDletStateChangeException(e.getMessage());
		} catch (RecordStoreException e) {
			throw new MIDletStateChangeException(e.getMessage());
		}
	}

	private void openDatabase() {
		try {
			recordStore = RecordStore.openRecordStore("MyRecordStore", false);
			System.out.println("Database already existed and contained " 
					+ recordStore.getNumRecords() + " records");
		} catch (RecordStoreNotFoundException e) {
			try {
				// If the database did not exist, create and populate it with sample data
				System.out.println("Creating and populating database");
				recordStore = RecordStore.openRecordStore("MyRecordStore", true);
				
				Person personA = new Person("Jack", 20);
				Person personB = new Person("Mary", 28);
				Person personC = new Person("Mike", 17);
				
				byte [] record = personA.serialize();
				recordStore.addRecord(record, 0, record.length);
				record = personB.serialize();
				recordStore.addRecord(record, 0, record.length);
				record = personC.serialize();
				recordStore.addRecord(record, 0, record.length);
			} catch (RecordStoreException e1) {
				throw new RuntimeException(e.getMessage());
			}
		} catch (RecordStoreFullException e) {
			throw new RuntimeException(e.getMessage());
		} catch (RecordStoreException e) {
			throw new RuntimeException(e.getMessage());
		}
		
		try {
			RecordStoreListener listener = new RecordStoreListener(System.out);
			recordStore.addRecordListener(listener);
			int size = recordStore.getSize();
			int avail = recordStore.getSizeAvailable();
			System.out.println("Database " + recordStore.getName() + " is open. Size/Available : ["
					+ size + "/" + avail + "(" + (100*size)/avail + "%)] Last modified : "
					+ new Date(recordStore.getLastModified()));
		} catch (RecordStoreNotOpenException e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	private void closeDatabase() {
		try {
			System.out.println("Closing database");
			recordStore.closeRecordStore();
		} catch (RecordStoreNotOpenException e) {
			throw new RuntimeException(e.getMessage());
		} catch (RecordStoreException e) {
			throw new RuntimeException(e.getMessage());
		}
	}

}
